#include <node.h>
#include <v8.h>
#include <string>
#include "calc.h"

using namespace std;
using namespace v8;

namespace lama{
    
	void Hello(const FunctionCallbackInfo<Value>& args)
	{
		Isolate* isolate=args.GetIsolate();
		args.GetReturnValue().Set(String::NewFromUtf8(isolate,"hello,world"));
	}
	
    void Add(const FunctionCallbackInfo<Value>& args)
    {
        Isolate* isolate=args.GetIsolate();   
        
        string errMsg="";
        if(args.Length()<2)
        {
           errMsg="参数个数错误";
        }
        
        if(!args[0]->IsNumber()||!args[1]->IsNumber())
        {
            errMsg="参数类型错误，必须为数字";
        }
        if(errMsg != "")
        {
            isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate,errMsg.c_str())));
            return;
        }
        
        double value=args[0]->NumberValue()+args[1]->NumberValue();
        Local<Number> num = Number::New(isolate,value);

        args.GetReturnValue().Set(num);        
    }
    
    void Sub(const FunctionCallbackInfo<Value>& args)
    {
        Isolate* isolate=args.GetIsolate();
        
        string errMsg="";
        if(args.Length()<2)
        {
           errMsg="参数个数错误";
        }
        
        if(!args[0]->IsNumber()||!args[1]->IsNumber())
        {
            errMsg="参数类型错误，必须为数字";
        }
        if(errMsg != "")
        {
            isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate,errMsg.c_str())));
            return;
        }
        
        double value=args[0]->NumberValue()-args[1]->NumberValue();
        
        Local<Function> cb=Local<Function>::Cast(args[2]);
        const unsigned argc=1;
        Local<Value> argv[argc]={Number::New(isolate,value)};;
        
        cb->Call(Null(isolate),argc,argv);        
    }
    
    
    void Mul(const FunctionCallbackInfo<Value>& args)
    {
        Isolate* isolate=args.GetIsolate();   
        
        double value=args[0]->NumberValue() * args[1]->NumberValue();
        
        Local<Object> obj=Object::New(isolate);
        obj->Set(String::NewFromUtf8(isolate, "type"), String::NewFromUtf8(isolate,"mul"));
        obj->Set(String::NewFromUtf8(isolate, "value"),Number::New(isolate,value));
        
        args.GetReturnValue().Set(obj);
    }
    
    void _div(const FunctionCallbackInfo<Value>& args)
    {
        Isolate* isolate=args.GetIsolate();
        double value=args[0]->NumberValue() / args[1]->NumberValue();
        args.GetReturnValue().Set(Number::New(isolate,value));
        
    }
    void Div(const FunctionCallbackInfo<Value>& args)
    {
        Isolate* isolate=args.GetIsolate();
        Local<FunctionTemplate> tpl=FunctionTemplate::New(isolate,_div);
        Local<Function> fn=tpl->GetFunction();
        
        fn->SetName(String::NewFromUtf8(isolate,"div")); 
        
        args.GetReturnValue().Set(fn);
    }
    
    
	void init(Local<Object> exports,Local<Object> module)
	{
		NODE_SET_METHOD(exports,"hello",Hello);
        NODE_SET_METHOD(exports,"add",Add);
        NODE_SET_METHOD(exports,"sub",Sub);
        NODE_SET_METHOD(exports,"mul",Mul);
        NODE_SET_METHOD(exports,"div",Div);
        
        Calc::Init(exports);
        
	}
    /*
        模块导出
    */
	NODE_MODULE(lama,init)
}